{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 安装 mindquantum, networkx\n",
    "!pip install mindquantum -i https://pypi.mirrors.ustc.edu.cn/simple\n",
    "!pip install networkx -i https://pypi.mirrors.ustc.edu.cn/simple"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 编程实践：量子模拟器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Numpy 是一个功能强大的Python库，主要用于对多维数组执行计算。\n",
    "# Simulator 是模拟器，可以模拟量子计算机的计算过程。\n",
    "import numpy as np                          # 导入numpy库并简写为np\n",
    "from mindquantum.simulator import Simulator # 导入模拟器\n",
    "\n",
    "# Simulator 中维护着一个量子态，初始为|0⟩态。\n",
    "sim = Simulator('mqvector', 1)  # 实例化'mqvector'模拟器,量子比特数为1\n",
    "print(sim)                      # 打印模拟器信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 通过 set_qs() 可以将量子态设置为任意的非零列向量，接口会自动进行归一化。\n",
    "plus_state = np.array([1, 1])   # 构造¦+⟩态\n",
    "sim.set_qs(plus_state)          # 将量子态设置为¦+⟩态\n",
    "\n",
    "quantum_state = sim.get_qs()    # 获取当前量子态\n",
    "ket = sim.get_qs(ket=True)      # 获取当前量子态的狄拉克符号形式\n",
    "print('quantum state:', quantum_state)\n",
    "print('ket:\\n', ket)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 编程实践：量子门"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from mindquantum.core.gates import X, Y, H      # 导入量子门\n",
    "from mindquantum.simulator import Simulator     # 导入模拟器\n",
    "\n",
    "# 每个量子门都有 matrix() 方法，可以获取该量子门的矩阵形式。\n",
    "print('Gate name:', X)\n",
    "gateX = X.matrix()\n",
    "print(gateX)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('Gate name:', Y)\n",
    "gateY = Y.matrix()\n",
    "print(gateY)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('Gate name:', H)\n",
    "gateH = H.matrix()\n",
    "print(gateH)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 调用 Simulator 的 apply_gate() 接口可以将量子门作用在量子比特上，使量子态发生演化。\n",
    "# on() 方法可以指定量子门作用在哪个量子比特上（目标比特），受哪些比特控制（控制比特）。\n",
    "sim = Simulator('mqvector', 1)          # 实例化一个模拟器\n",
    "sim.apply_gate(H.on(0))                 # 将H门作用于q0\n",
    "print(sim)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 编程实践：量子线路"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from mindquantum.core.gates import X, Y, H   # 导入量子门X, Y, H\n",
    "from mindquantum.core.circuit import Circuit # 导入Circuit模块，用于搭建量子线路\n",
    "from mindquantum.simulator import Simulator  # 导入模拟器\n",
    "\n",
    "# 通过“+=”的方式可以轻松地将量子门添加到量子线路中。\n",
    "circ = Circuit() \t\t\t# 实例化一个量子线路\n",
    "circ += H.on(0)  \t\t\t# 在线路上的第0个比特添加一个H门\n",
    "circ += Y.on(0) \t\t\t# 在线路上的第0个比特添加一个Y门\n",
    "circ += X.on(1) \t\t\t# 在线路上的第1个比特添加一个X门\n",
    "\n",
    "print(circ)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mat = circ.matrix() \t\t# 获取线路对应的矩阵\n",
    "print('circuit matrix:\\n', mat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 调用 Simulator 的 apply_circuit() 接口可以将量子线路作用在量子比特上，使量子态发生演化。\n",
    "sim = Simulator('mqvector', 2)  \t# 实例化一个两比特的模拟器\n",
    "sim.apply_circuit(circ)          \t# 作用量子线路\n",
    "print(sim)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 编程实践：量子测量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from mindquantum.core.gates import Measure, H, X, Y # 导入量子门X, Y, H和量子测量Measure\n",
    "from mindquantum.core.circuit import Circuit        # 导入Circuit模块，用于搭建量子线路\n",
    "from mindquantum.simulator import Simulator         # 导入模拟器\n",
    "\n",
    "circ = Circuit()                    # 实例化一个量子线路\n",
    "circ += H.on(0)                     # 在线路上的第0个比特添加一个H门\n",
    "circ += Y.on(0)                     # 在线路上的第0个比特添加一个Y门\n",
    "circ += X.on(1)                     # 在线路上的第1个比特添加一个X门\n",
    "\n",
    "# Measure 与量子门类似，可以用“+=”的方式添加到量子线路中，用 on() 方法指定目标比特。\n",
    "circ += Measure().on(0)             # 在线路上的第0个比特添加一个测量\n",
    "circ += Measure().on(1)             # 在线路上的第1个比特添加一个测量\n",
    "\n",
    "print(circ)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 调用 Simulator 的 sampling() 接口可以对某一线路的演化结果进行多次采样，获得量子测量的统计结果。\n",
    "# 这一过程与真实量子计算机的运行方式相似。\n",
    "sim = Simulator('mqvector', 2)              # 实例化一个两比特的模拟器\n",
    "result = sim.sampling(circ, shots=1000) \t# 对该线路的演化结果进行1000次采样\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 编程实践：量子近似优化算法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from mindquantum.algorithm import MaxCutAnsatz\n",
    "from mindquantum.core.operators import Hamiltonian, QubitOperator\n",
    "from mindquantum.framework import MQAnsatzOnlyLayer\n",
    "import networkx as nx\n",
    "import mindspore.nn as nn\n",
    "\n",
    "# 构造待求解图\n",
    "graph = nx.Graph([(0, 1), (1, 2), (2, 3), (3, 4), (0, 4), (0, 2)])\n",
    "nx.draw(graph, with_labels=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将图转化为目标哈密顿量\n",
    "pauli_ops = QubitOperator()\n",
    "for i in graph.edges:\n",
    "    pauli_ops += QubitOperator(f'Z{i[0]} Z{i[1]}')\n",
    "ham = Hamiltonian(pauli_ops)\n",
    "\n",
    "# 构造线路\n",
    "circ = MaxCutAnsatz(list(graph.edges), depth=4).circuit\n",
    "circ.svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建模拟器，backend使用‘mqvector’，能模拟5个比特（'circ'线路中包含的比特数）\n",
    "sim = Simulator(\"mqvector\", 5)\n",
    "\n",
    "# 生成计算变分量子线路的期望值和梯度的算子\n",
    "grad_ops = sim.get_expectation_with_grad(ham, circ)\n",
    "\n",
    "# 生成待训练的神经网络\n",
    "net = MQAnsatzOnlyLayer(grad_ops)\n",
    "\n",
    "# 设置针对网络中所有可训练参数、学习率为0.05的Adam优化器\n",
    "opti = nn.Adam(net.trainable_params(), learning_rate=0.05)\n",
    "\n",
    "# 生成能对神经网络进行一步训练的算子\n",
    "train_net = nn.TrainOneStepCell(net, opti)\n",
    "\n",
    "for i in range(200):\n",
    "\n",
    "    # 将神经网络训练一步并计算得到的结果（切割边数）。注意：每当'train_net()'运行一次，神经网络就训练了一步\n",
    "    cut = (len(graph.edges) - train_net()) / 2\n",
    "\n",
    "    # 每训练10步，打印当前训练步数和当前得到的切割边数\n",
    "    if i % 10 == 0:\n",
    "        print(\"train step:\", i, \", cut:\", cut)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "mq",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
